<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="bulma.min.css">
    <title>MeiliSearch</title>
    <style>
      em {
        color: hsl(204, 86%, 25%);
        font-style: inherit;
        background-color: hsl(204, 86%, 88%);
      }

      #results {
        max-width: 900px;
        margin: 20px auto 0 auto;
        padding: 0;
      }

      .notification {
        display: flex;
        justify-content: center;
      }

      .level-left {
        margin-right: 50px;
      }

      .document {
        border-radius: 4px;
        margin-bottom: 20px;
        display: flex;
      }

      .document ol {
        flex: 0 0 75%;
        max-width: 75%;
        padding: 0;
        margin: 0;
        list-style-type: none;
      }

      .document ol li {
        list-style: none;
      }


      .document .image {
        max-width: 50%;
        margin: 0 auto;
        box-sizing: border-box;
      }

      @media screen and (min-width: 770px) {
        .document .image {
          max-width: 25%;
          flex: 0 0 25%;
          margin: 0;
          padding-left: 30px;
          box-sizing: border-box;
        }
      }

      .document .image img {
        width: 100%;
      }

      .attribute {
        text-align: center;
        box-sizing: border-box;
        text-transform: uppercase;
        font-weight: bold;
        color: rgba(0,0,0,.7);
      }

      @media screen and (min-width: 770px) {
        .attribute {
          flex: 0 0 25%;
          max-width: 25%;
          text-align: right;
          padding-right: 10px;
          font-weight: normal;
          box-sizing: border-box;
        }
      }
      @media screen and (max-width: 770px) {
        .attribute {
          padding-bottom: 0;
        }
      }

      .content {
        flex: 0 0 75%;
        box-sizing: border-box;
        color: rgba(0,0,0,.9);
        overflow-wrap: anywhere;
      }

      .hero-foot {
        padding-bottom: 3rem;
      }

      @media screen and (max-width: 770px) {
        .align-on-mobile {
          text-align: center;
        }
      }
    </style>
  </head>
  <body>

    <section class="hero is-light">
      
      <div class="hero-body">
        <div class="container">
          <div class="content is-medium align-on-mobile">
            <h1 class="title is-1 is-spaced">
              Welcome to MeiliSearch
            </h1>
            <p class="subtitle is-4">
              This dashboard will help you check the search results with ease.
            </p>
          </div>
          <div id="apiKeyContainer" class="columns">
            <input type="hidden" id="apiKey">
          </div>
          <div class="columns">
            <div class="column is-8">
                <label class="label" for="search">Search something</label>
                <div class="field has-addons">
                  <div class="control">
                    <span class="select">
                      <select role="listbox" id="index" aria-label="Select the index you want to search on">
                        <!-- indexes names -->
                      </select>
                    </span>
                  </div>
                  <div class="control is-expanded">
                    <input id="search" class="input" type="search" autofocus placeholder="e.g. George Clooney" aria-label="Search through your documents">
                  </div>
                </div>
            </div>
            <div class="column is-4">
              <div class="columns">
                <div class="column is-6 has-text-centered">
                  <p class="heading">Documents</p>
                  <p id="count" class="title">0</p>
                </div>
                <div class="column is-6 has-text-centered">
                  <p class="heading">Time Spent</p>
                  <p id="time" class="title">N/A</p>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>

    <section>
      <div class="container">
        <ol id="results" class="content">
          <!-- documents matching resquests -->
        </ol>
      </div>
    </section>
  </body>

  <script>
    function setApiKeyField () {
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.open("GET", `${baseUrl}/version`, false);
        
        xmlHttp.onload = function () {
            let apiKeyContainer = document.getElementById('apiKeyContainer');
            if (xmlHttp.status === 401) {
                document.getElementById('apiKey').remove();
                let inputNode = document.createElement('input');
                inputNode.setAttribute('id', 'apiKey');
                inputNode.setAttribute('type', 'password');
                inputNode.setAttribute('placeholder', 'Enter your API key');
                inputNode.classList.add('input', 'is-small');

                let controlNode = document.createElement('div');
                controlNode.classList.add('control');
                controlNode.appendChild(inputNode);

                let labelNode = document.createElement('label');
                labelNode.classList.add('label')
                labelNode.setAttribute('for', 'apiKey');
                let textNode = document.createTextNode('API Key');
                labelNode.appendChild(textNode);

                let fieldNode = document.createElement('div');
                fieldNode.classList.add('field');
                fieldNode.appendChild(labelNode);
                fieldNode.append(controlNode);

                let columnNode = document.createElement('div');
                columnNode.classList.add('column', 'is-4');
                columnNode.appendChild(fieldNode);
                apiKeyContainer.appendChild(columnNode);
            }
        }
        
        xmlHttp.send(null);
    }

    function sanitizeHTMLEntities(str) {
        if (str && typeof str === 'string') {
            str = str.replace(/</g,"&lt;");
            str = str.replace(/>/g,"&gt;");
            str = str.replace(/&lt;em&gt;/g,"<em>");
            str = str.replace(/&lt;\/em&gt;/g,"<\/em>");
        }
        return str;
    }

    function httpGet(theUrl, apiKey) {
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.open("GET", theUrl, false); // false for synchronous request
        if (apiKey) {
          xmlHttp.setRequestHeader("x-Meili-API-Key", apiKey);
        }
        xmlHttp.send(null);
        return xmlHttp.responseText;
    }

    function refreshIndexList() {
        // TODO we must not block here
        let result = JSON.parse(httpGet(`${baseUrl}/indexes`, localStorage.getItem('apiKey')));

        if (!Array.isArray(result)) { return }

        let select = document.getElementById("index");
        select.innerHTML = '';

        for (index of result) {
            const option = document.createElement('option');
            option.value = index.uid;
            option.innerHTML = index.name;
            select.appendChild(option);
        }
    }

    let lastRequest = undefined;

    function triggerSearch() {
        var e = document.getElementById("index");
        if (e.selectedIndex == -1) { return }
        var index = e.options[e.selectedIndex].value;

        let theUrl = `${baseUrl}/indexes/${index}/search?q=${encodeURIComponent(search.value)}&attributesToHighlight=*`;

        if (lastRequest) { lastRequest.abort() }
        lastRequest = new XMLHttpRequest();

        lastRequest.open("GET", theUrl, true);

        if (localStorage.getItem('apiKey')) {
          lastRequest.setRequestHeader("x-Meili-API-Key", localStorage.getItem('apiKey'));
        }

        lastRequest.onload = function (e) {
            if (lastRequest.readyState === 4 && lastRequest.status === 200) {
                let sanitizedResponseText = sanitizeHTMLEntities(lastRequest.responseText);
                let httpResults = JSON.parse(sanitizedResponseText);
                results.innerHTML = '';

                let processingTimeMs = httpResults.processingTimeMs;
                let numberOfDocuments = httpResults.nbHits;
                time.innerHTML = `${processingTimeMs}ms`;
                count.innerHTML = `${numberOfDocuments}`;

                for (result of httpResults.hits) {
                    const element = {...result, ...result._formatted };
                    delete element._formatted;

                    const elem = document.createElement('li');
                    elem.classList.add("document","box");

                    const div = document.createElement('div');
                    div.classList.add("columns","is-desktop","is-tablet");
                    const info = document.createElement('div');
                    info.classList.add("column","align-on-mobile");
                    let image = undefined;

                    for (const prop in element) {
                        // Check if property is an image url link.
                        if (typeof result[prop] === 'string') {
                            if (image == undefined && result[prop].match(/^(https|http):\/\/.*(jpe?g|png|gif)(\?.*)?$/g)) {
                                image = result[prop];
                            }
                        }

                        const field = document.createElement('div');
                        field.classList.add("columns");

                        const attribute = document.createElement('div');
                        attribute.classList.add("attribute", "column");
                        attribute.innerHTML = prop;

                        const content = document.createElement('div');
                        content.classList.add("content", "column");
                        
                        if (typeof (element[prop]) === "object") {
                          content.innerHTML = JSON.stringify(element[prop]);
                        } else {
                          content.innerHTML = element[prop];
                        }

                        field.appendChild(attribute);
                        field.appendChild(content);

                        info.appendChild(field);
                    }

                    div.appendChild(info);
                    elem.appendChild(div);

                    if (image != undefined) {
                        const divImage = document.createElement('div');
                        divImage.classList.add("image","column","align-on-mobile");
                        
                        const img = document.createElement('img');
                        img.src = image;
                        img.setAttribute("alt","Item illustration");

                        divImage.appendChild(img);
                        div.appendChild(divImage);
                        elem.appendChild(div);
                    }

                    results.appendChild(elem)
                }
            } else {
                console.error(lastRequest.statusText);
            }
        };
        lastRequest.send(null);
    }

    if (!apiKey.value) {
        apiKey.value = localStorage.getItem('apiKey');
    }

    apiKey.addEventListener('input', function(e) {
        localStorage.setItem('apiKey', apiKey.value);
        refreshIndexList();
    }, false);

    let baseUrl = window.location.origin;
    setApiKeyField();
    refreshIndexList();

    search.oninput = triggerSearch;
    
    let select = document.getElementById("index");
    select.onchange = triggerSearch;

    triggerSearch();
  </script>
</html>
